#include "onewire.h"

#define LED_B_PIN GPIO_PIN_2
#define LED_B_BASE GPIO_PORTF_BASE

bool_t owDevicesPresent = false;
bool_t owBusy;
bool_t owReading = false;
unsigned long long caminos=0;

uint8_t discrepancias[MAXDISPOSITIVOS];
uint8_t dispositivosEncontrados = 0;
owDevice_t *owDevices;
extern uint32_t uiDeviceSampleTime;



void owInit(void)
{
	owDevicesPresent = owReset();
}

bool_t owReset()
{
// #TODO agregar timeouts para no bloquear en dummy
	bool_t retVal = true;
	while(owBusy);
	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, !GPIO_PIN_0);
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 700*CLOCKSXuSEC);
	ROM_TimerEnable(TIMER0_BASE, TIMER_A);
	owBusy = 1;
	while(owBusy);
	ROM_GPIOPinTypeGPIOInput(GPIO_PORTB_BASE, GPIO_PIN_0);
	while(retVal)
	{
		retVal = (GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_0)&GPIO_PIN_0)==0 ? true : false;
	}
	ROM_GPIOPinTypeGPIOOutputOD(GPIO_PORTB_BASE, GPIO_PIN_0);
	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, GPIO_PIN_0);
	owBusy = 1;
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 500*CLOCKSXuSEC);
	ROM_TimerEnable(TIMER0_BASE, TIMER_A);
	return retVal;
}

error_t owSearchRom(owDevice_t *newdevices, uint8_t * encontrados)
{
	uint32_t aux=0;
	uint8_t bifurcaciones[MAXDISPOSITIVOS];
	uint8_t indiceBifurcaciones = 0;
	for (aux = 0; aux < MAXDISPOSITIVOS ; aux++)
	{
		bifurcaciones[aux] = 65;
	}
	// #TODO agregar timeouts para no bloquear en dummy
	dispositivosEncontrados = 0;
	caminos = 0;
	if( ret_Ok != owSendBif(newdevices, bifurcaciones, &indiceBifurcaciones, 0))
	{
		return ret_error;
	}
	*encontrados = dispositivosEncontrados;
	return ret_Ok;
}

static error_t
    owSendBif (owDevice_t *devOW, uint8_t *bifurcaciones, uint8_t *indiceBifurcaciones, uint8_t discrepPadre)
{
	bool_t BitLeido, BitLeidoCmp;
	uint8_t bits;
	uint8_t* actAddr;
	uint8_t ultimaBif = 0;
	uint8_t discrepanciasLocales = 0;
	error_t retVal;

	actAddr = (uint8_t*)&(devOW[dispositivosEncontrados].romAddr);
	owSendCmd(0xF0);

	for (bits=0;bits<64; bits++)
	{
		BitLeido = owRDBit();
		BitLeidoCmp = owRDBit();
		while(owBusy);		//SOLO PARA PODER DEPURAR
		if (BitLeido==true)
		{
			if(BitLeidoCmp==true)
			{
				return ret_NotFound;
			}
			else
			{
				actAddr[bits/8] |= 1<<(bits%8);
				owWRBit(true);
			}
		}
		else
		{
			if(BitLeidoCmp==true)
			{
				actAddr[bits/8] &= ~(1<<(bits%8));
				owWRBit(false);
			}
			else
			{
				if((caminos & ((unsigned long long)1<<bits))!=0) //si est� marcado, tomar el camino por 1
				{

					actAddr[bits/8] |= 1<<(bits%8);
					owWRBit(true);
				}
				else
				{
					actAddr[bits/8] &= ~(1<<(bits%8));
					owWRBit(false);
				}
				while(owBusy);		//SOLO PARA PODER DEPURAR
				if(discrepPadre < bits)	// nueva bifurcaci�n
				{
					discrepanciasLocales++;
					bifurcaciones[(*indiceBifurcaciones)++] = (uint8_t)bits;
					if(*indiceBifurcaciones >= MAXDISPOSITIVOS)
						return ret_ToMuchDevices;
					ultimaBif = bits;
				}
			}
		}
	}
	dispositivosEncontrados++;
	while(discrepanciasLocales>0)
	{
		bits = bifurcaciones[(*indiceBifurcaciones)-1];
		caminos |= 1<<bits;
		owReset();
		retVal = owSendBif(devOW,bifurcaciones, indiceBifurcaciones, bits);
		if (retVal != ret_Ok)
			return retVal;
		caminos &= ~(1<<bits);
		(*indiceBifurcaciones)--;
		discrepanciasLocales--;

	}
	return ret_Ok;
}

error_t owSendCmd(uint8_t cmd)
{
	uint8_t bMask;
	for (bMask = 1; bMask; bMask<<=1)
	{
		while(owBusy);
		if (cmd & bMask)
			owWRBit(true);
		else
			owWRBit(false);
	}
	return ret_Ok;
}

static bool_t owRDBit()
{
	bool_t retVal;
	//bool_t waitUp;
	while(owBusy);
	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, !GPIO_PIN_0);
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 3*CLOCKSXuSEC);	//tiempo master pulling down
	owBusy = 1;
	owReading = true;
	uiDeviceSampleTime =0;
	ROM_TimerEnable(TIMER0_BASE, TIMER_A);
	while(owBusy);
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 10*CLOCKSXuSEC); // demora antes de leer
	ROM_TimerEnable(TIMER0_BASE, TIMER_A);
	owBusy = 1;
	while(owBusy);
	ROM_GPIOPinTypeGPIOInput(GPIO_PORTB_BASE, GPIO_PIN_0);
	retVal = (GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_0)&GPIO_PIN_0)==0? false:true;
	owWaitPin(100);
	/*	waitUp = retVal;
	while(!waitUp)
	{
		waitUp = (GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_0)&GPIO_PIN_0)==0? false:true;
	}
	ROM_GPIOPinTypeGPIOOutputOD(GPIO_PORTB_BASE, GPIO_PIN_0);
	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, GPIO_PIN_0);*/
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, 70*CLOCKSXuSEC); // para leer pr�ximo dato
	ROM_TimerEnable(TIMER0_BASE, TIMER_A);
	owBusy = 1;
	return retVal;
}

static void owWRBit(bool_t bVal)
{
	uint32_t uiDelay;
	while(owBusy);
	uiDelay = (bVal == true) ? 10*CLOCKSXuSEC : 60*CLOCKSXuSEC;
	uiDeviceSampleTime = (bVal == true) ? 80*CLOCKSXuSEC : 40*CLOCKSXuSEC;
	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, !GPIO_PIN_0);
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, uiDelay);
	ROM_TimerEnable(TIMER0_BASE, TIMER_A);
	owBusy = 1;
}

error_t owSendMatchRom(owDevice_t * sensor)
{
	error_t retVal;
	uint8_t i;
	retVal = owSendCmd(0x55);
	for (i = 0; i < 8; i++)
	{
		retVal = owSendCmd(sensor->romAddr[i]);
	}
	return retVal;
}

error_t owReadBytes(uint8_t cantidad, uint8_t* buff)
{
	error_t retVal=ret_Ok;
	uint8_t i=0;
	while(owBusy);
	while(cantidad && retVal == ret_Ok){
		retVal = owReadByte((uint8_t*)(buff+i));
		i++;
		cantidad--;
	}
	return retVal;
}

error_t owReadByte(uint8_t * dato)
{
	uint8_t i;
	*dato = 0;
	for(i=1;i;i<<=1)
	{
		if(owRDBit())
		{
			*dato |= i;
		}
	}
	return ret_Ok;
}

error_t owWaitPin(uint32_t timeout)
{
	bool_t waitUp;
	while(owBusy);
	ROM_TimerLoadSet(TIMER0_BASE, TIMER_A, timeout*CLOCKSXuSEC);	//tiempo máximo esperando que se libere
	ROM_TimerEnable(TIMER0_BASE, TIMER_A);
	owBusy = 1;
	ROM_GPIOPinTypeGPIOInput(GPIO_PORTB_BASE, GPIO_PIN_0);
	waitUp = (GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_0)&GPIO_PIN_0)==0? false:true;
	while(!waitUp && owBusy)
	{
		waitUp = (GPIOPinRead(GPIO_PORTB_BASE, GPIO_PIN_0)&GPIO_PIN_0)==0? false:true;
	}
	if(!owBusy)
	{
		return ret_TimeOut;
	}
	ROM_GPIOPinTypeGPIOOutputOD(GPIO_PORTB_BASE, GPIO_PIN_0);
	GPIOPinWrite(GPIO_PORTB_BASE, GPIO_PIN_0, GPIO_PIN_0);
	return ret_Ok;
}
